package com.xiao.ojbakcendgateway.filter;

import cn.hutool.core.text.AntPathMatcher;
import com.alibaba.nacos.common.utils.StringUtils;
import com.xiao.common.common.ErrorCode;
import com.xiao.common.utils.JwtUtils;
import com.xiao.model.entity.User;
import com.xiao.ojbakcendserviceclient.service.UserFeignClient;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;


@Component
public class JwtAuthFilter implements GlobalFilter, Ordered {

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private UserFeignClient userFeignClient; // 调用用户服务的Feign客户端

    // 无需验证Token的路径（登录、注册、内部接口等）
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/api/user/login",
            "/api/user/register",
            "/api/user/logout",
            "/api/user/get/login",
            "/api/question/update",
            "/api/question/**/list/**",
            "/api/**/v2/api-docs",      // 三个模块通用文档路径
            "/doc.html",                // Knife4j文档入口
            "/**/inner/**",            // 内部服务调用接口

            // 前端路由路径
            "/",
            "/user/login",
            "/user/register",
            "/questions",
            "/questions_submit",
            "/view/question/**",
            "/add/question",
            "/update/question",
            "/manage/question",
            "/noAuth"
    );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 白名单路径直接放行（包含接口文档路径）
        if (WHITE_LIST.stream().anyMatch(whitePath ->
                new AntPathMatcher().match(whitePath, path))) {
            return chain.filter(exchange);
        }

        // 从请求头获取Token
        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isBlank(token) || !token.startsWith("Bearer ") ) {
            return handleUnauthorized(exchange, "未提供有效Token");
        }
        token = token.substring(7);

        // 验证Token有效性
        if (!jwtUtils.validateToken(token)) {
            return handleUnauthorized(exchange, "Token无效或已过期");
        }

        // 解析Token获取用户ID和角色
        try {
            Long userId = jwtUtils.getUserId(token);
            String userRole = jwtUtils.getUserRole(token);

            // 调用用户服务验证用户是否存在（通过Feign，避免直接依赖用户服务）
            User user = userFeignClient.getById(userId);
            if (user == null) {
                return handleUnauthorized(exchange, "用户不存在");
            }

            // 将用户信息存入请求头，供下游服务使用（替代Session）
            ServerHttpRequest modifiedRequest = request.mutate()
                    .header("X-User-Role", userRole)
                    .build();
            return chain.filter(exchange.mutate().request(modifiedRequest).build());

        } catch (Exception e) {
            return handleUnauthorized(exchange, "Token解析失败");
        }
    }

    // 处理未授权响应
    private Mono<Void> handleUnauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        String json = "{\"code\":" + ErrorCode.NOT_LOGIN_ERROR.getCode()
                + ",\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return 1;           // 执行顺序在GlobalAuthFilter之后（先过滤内部接口，再验证Token）
    }
}

